#ifndef __CUDA_HOOK_MACRO_H__
#define __CUDA_HOOK_MACRO_H__

#include <time.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

/* 在 C 和 C++ 中，#include <sys/syscall.h> 这个头文件主要用于提供对 Linux 系统调用接口的访问。
系统调用是应用程序与操作系统之间进行通信的一种方式，允许应用程序请求操作系统提供的底层服务，如文件操作、
进程管理、网络通信等。*/
#include <sys/types.h>
#include <sys/syscall.h>


/** __attribute__((visibility("default")))：这是一个 GCC 特有的属性指定语法，用于控制函数、变量或类型的可见性。
**    visibility("default")：这个属性设置使得函数或变量对所有其他模块都可见。这是与动态链接相关的概念。当你编译成
**    共享库（如 .so 文件）时，
**    
**    - visibility("default") 表明这个函数或变量可以被库的用户访问
**    - visibility("hidden")，后者意味着函数或变量只在定义它们的库内部可见
**
**    这种方式常用于控制库的 API 公开的部分。例如，你可能有一些内部函数你不想公开，但有些接口函数是你希望库的用户能够使
**    用的。使用 __attribute__((visibility("default"))) 可以帮助减小最终库的大小，并优化动态链接的性能，因为它减
**    少了库间的符号解析工作量。
*/
#define HOOK_C_API extern "C"
#define HOOK_DECL_EXPORT __attribute__((visibility("default")))


/**
 * 这段代码定义了一个名为HOOK_LIKELY的宏，它接受一个参数x。通常，这种宏用于性能优化，特别是在有条件语句（如if-else）
    的情况下，你想向编译器提供关于条件可能的结果的提示。以下是它的详细解释：

    - !!(x): 这部分宏双重否定了表达式x。它将任何非零值转换为1，将零值转换为0。这是为了确保参数x是一个布尔表达式。

    - __builtin_expect(!!(x), 1): 这是GCC编译器的内置函数（因此在开头和结尾有双下划线），它向编译器提供关于预
      期分支结果的提示。它接受两个参数：布尔表达式!!(x)和预期结果1（表示“可能为真”）。

    因此，当你在代码中像这样使用这个宏：
        if (HOOK_LIKELY(some_condition)) {
            // 如果some_condition可能为真，则执行这里的代码
        } else {
            // 如果some_condition可能为假，则执行这里的代码
        }

    它告诉编译器你期望some_condition大部分时间为真，编译器可以相应地优化代码。这可以在提示准确的情况下提高性能。

    ** 需要注意的是，这段代码特定于GCC编译器（或支持__builtin_expect函数的编译器），在其他编译器如Microsoft 
        Visual C++中可能不起作用。
 */
#define HOOK_LIKELY(x)   __builtin_expect(!!(x), 1)
#define HOOK_UNLIKELY(x) __builtin_expect(!!(x), 0)


inline char *curr_time() {
    time_t raw_time = time(nullptr);
    struct tm *time_info = localtime(&raw_time);
    static char now_time[64];
    now_time[strftime(now_time, sizeof(now_time), "%Y-%m-%d %H:%M:%S", time_info)] = '\0';

    return now_time;
}

inline int get_pid() {
    // 获取当前进程id: #include <unistd.h>
    static int pid = getpid(); 
    return pid;
}

inline long int get_tid() {
    // 获取当前线程id: #include <sys/syscall.h>
    thread_local long int tid = syscall(SYS_gettid);
    return tid;
}


#define HOOK_LOG_TAG "CUDA-HOOK"
// char *strrchr(const char *str, int character);
// 找到某个字符在字符串的最后一次出现的位置，如果找到返回当前位置以后的内容，未找到返回空
#define HOOK_LOG_FILE(x) (strrchr(x, '/') ? (strrchr(x, '/') + 1) : x)
#define HLOG(format, ...)                                                          \
    do {                                                                           \
        fprintf(stderr, "[%s %s %d:%ld %s:%d %s] " format "\n",                    \
                HOOK_LOG_TAG, curr_time(), get_pid(), get_tid(),                   \
                HOOK_LOG_FILE(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__);   \
    } while (0)

#define HOOK_CHECK(x)                           \
    do {                                        \
        if (HOOK_UNLIKELY(!(x))) {              \
            HLOG("Check failed: %s", #x);       \
            exit(EXIT_FAILURE);                 \
        }                                       \
    } while (0)

// 禁止拷贝和复制构造函数
#define HOOK_DISABLE_COPY_AND_ASSIGN(TypeName)  \
    TypeName(const TypeName &)       = delete;  \
    void operator=(const TypeName &) = delete;


#endif // __CUDA_HOOK_MACRO_H__